.quad 0x00cff2000000bfff /* 0x2b ring 3 3.95GB data at 0x0 */
.quad 0x00cf9a000000ffff /* 0x30 ring 0 4.00GB code at 0x0 */
.quad 0x00cf92000000ffff /* 0x38 ring 0 4.00GB data at 0x0 */
- .quad 0x0000000000000000
- .quad 0x0000000000000000
- .quad 0x0000000000000000
- .quad 0x0000000000000000
- .fill NR_CPUS*4,8,0 /* space for TSS's and LDT's */
+ .fill NR_CPUS,8,0 /* space for TSS's */
# The following adds 12kB to the kernel file size.
.org 0x1000
.long SYMBOL_NAME(do_set_trap_table)
.long SYMBOL_NAME(do_process_page_updates)
.long SYMBOL_NAME(do_console_write)
- .long SYMBOL_NAME(sys_ni_syscall)
- .long SYMBOL_NAME(do_set_guest_stack)
+ .long SYMBOL_NAME(do_set_gdt)
+ .long SYMBOL_NAME(do_stack_and_ldt_switch)
.long SYMBOL_NAME(do_net_update)
.long SYMBOL_NAME(do_fpu_taskswitch)
.long SYMBOL_NAME(do_yield)
.long SYMBOL_NAME(do_network_op)
.long SYMBOL_NAME(do_set_debugreg)
.long SYMBOL_NAME(do_get_debugreg)
+ .long SYMBOL_NAME(do_update_descriptor)
.rept NR_syscalls-(.-hypervisor_call_table)/4
.long SYMBOL_NAME(sys_ni_syscall)
.endr
}
-long do_set_guest_stack(unsigned long ss, unsigned long esp)
+long do_stack_and_ldt_switch(
+ unsigned long ss, unsigned long esp, unsigned long ldts)
{
int nr = smp_processor_id();
struct tss_struct *t = &init_tss[nr];
if ( (ss == __HYPERVISOR_CS) || (ss == __HYPERVISOR_DS) )
return -1;
+ if ( ldts != current->mm.ldt_sel )
+ {
+ unsigned long *ptabent = GET_GDT_ADDRESS(current);
+ /* Out of range for GDT table? */
+ if ( (ldts * 8) > GET_GDT_ENTRIES(current) ) return -1;
+ ptabent += ldts * 2; /* 8 bytes per desc == 2 * unsigned long */
+ /* Not an LDT entry? (S=0b, type =0010b) */
+ if ( (*ptabent & 0x00001f00) != 0x00000200 ) return -1;
+ current->mm.ldt_sel = ldts;
+ __load_LDT(ldts);
+ }
+
current->thread.ss1 = ss;
current->thread.esp1 = esp;
t->ss1 = ss;
return 0;
}
+
+
+long do_set_gdt(unsigned long *frame_list, int entries)
+{
+ return -ENOSYS;
+}
+
+
+long do_update_descriptor(
+ unsigned long pa, unsigned long word1, unsigned long word2)
+{
+ return -ENOSYS;
+}
asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs));
asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
+ /* Switch GDT and LDT. */
+ __asm__ __volatile__ ("lgdt %0" : "=m" (*next_p->mm.gdt));
+ __load_LDT(next_p->mm.ldt_sel);
+
/*
* Restore %fs and %gs.
*/
panic("CPU#%d already initialized!!!\n", nr);
printk("Initializing CPU#%d\n", nr);
- __asm__ __volatile__("lgdt %0": "=m" (gdt_descr));
+ /* Set up GDT and IDT. */
+ SET_GDT_ENTRIES(current, DEFAULT_GDT_ENTRIES);
+ SET_GDT_ADDRESS(current, DEFAULT_GDT_ADDRESS);
+ __asm__ __volatile__("lgdt %0": "=m" (*current->mm.gdt));
__asm__ __volatile__("lidt %0": "=m" (idt_descr));
/* No nested task. */
_set_tssldt_desc(gdt_table+__TSS(n), (int)addr, 235, 0x89);
}
-void set_ldt_desc(unsigned int n, void *addr, unsigned int size)
-{
- _set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82);
-}
-
void __init trap_init(void)
{
set_trap_gate(0,÷_error);
if (!p) goto newdomain_out;
memset(p, 0, sizeof(*p));
p->shared_info = (void *)get_free_page(GFP_KERNEL);
- memset(p->shared_info, 0, sizeof(shared_info_t));
+ memset(p->shared_info, 0, PAGE_SIZE);
+
+ SET_GDT_ENTRIES(p, DEFAULT_GDT_ENTRIES);
+ SET_GDT_ADDRESS(p, DEFAULT_GDT_ADDRESS);
p->addr_limit = USER_DS;
p->state = TASK_UNINTERRUPTIBLE;
{
destroy_net_vif(p);
}
+ if ( p->mm.perdomain_pt ) free_page((unsigned long)p->mm.perdomain_pt);
free_page((unsigned long)p->shared_info);
free_task_struct(p);
}
phys_l2tab = ALLOC_FRAME_FROM_DOMAIN();
l2tab = map_domain_mem(phys_l2tab);
memcpy(l2tab, idle_pg_table[p->processor], PAGE_SIZE);
+ l2tab[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ mk_l2_pgentry(__pa(p->mm.perdomain_pt) | __PAGE_HYPERVISOR);
memset(l2tab, 0, DOMAIN_ENTRIES_PER_L2_PAGETABLE*sizeof(l2_pgentry_t));
p->mm.pagetable = mk_pagetable(phys_l2tab);
memcpy(p_l2_entry,
idle_pg_table[smp_processor_id()] + DOMAIN_ENTRIES_PER_L2_PAGETABLE,
HYPERVISOR_ENTRIES_PER_L2_PAGETABLE * sizeof(l2_pgentry_t));
+ p_l2_entry[(PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT) -
+ DOMAIN_ENTRIES_PER_L2_PAGETABLE] =
+ mk_l2_pgentry(__pa(current->mm.perdomain_pt) | __PAGE_HYPERVISOR);
return(ret);
}
#ifndef __ARCH_DESC_H
#define __ARCH_DESC_H
-#define __FIRST_TSS_ENTRY 12
-#define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY+1)
-
-#define __TSS(n) (((n)<<2) + __FIRST_TSS_ENTRY)
-#define __LDT(n) (((n)<<2) + __FIRST_LDT_ENTRY)
+#define __FIRST_TSS_ENTRY 8
+#define __TSS(n) ((n) + __FIRST_TSS_ENTRY)
#ifndef __ASSEMBLY__
struct desc_struct {
#define load_TR(n) __asm__ __volatile__("ltr %%ax"::"a" (__TSS(n)<<3))
-#define __load_LDT(n) __asm__ __volatile__("lldt %%ax"::"a" (__LDT(n)<<3))
+#define __load_LDT(n) __asm__ __volatile__("lldt %%ax"::"a" ((n)<<3))
extern void set_intr_gate(unsigned int irq, void * addr);
-extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
extern void set_tss_desc(unsigned int n, void *addr);
#endif /* !__ASSEMBLY__ */
0,0,0,0, /* esp,ebp,esi,edi */ \
0,0,0,0,0,0, /* es,cs,ss */ \
0,0,0,0,0,0, /* ds,fs,gs */ \
- __LDT(0),0, /* ldt */ \
+ 0,0, /* ldt */ \
0, INVALID_IO_BITMAP_OFFSET, /* tace, bitmap */ \
{~0, } /* ioperm */ \
}
} page_update_request_t;
+/*
+ * Segment descriptor tables.
+ */
+/* 8 entries, plus a TSS entry for each CPU (up to 32 CPUs). */
+#define FIRST_DOMAIN_GDT_ENTRY 40
+/* These are flat segments for domain bootstrap and fallback. */
+#define FLAT_RING1_CS 0x11
+#define FLAT_RING1_DS 0x19
+#define FLAT_RING3_CS 0x23
+#define FLAT_RING3_DS 0x2b
+
+
/* EAX = vector; EBX, ECX, EDX, ESI, EDI = args 1, 2, 3, 4, 5. */
-#define __HYPERVISOR_set_trap_table 0
-#define __HYPERVISOR_pt_update 1
-#define __HYPERVISOR_console_write 2
-/* vector 3 unused */
-#define __HYPERVISOR_set_guest_stack 4
-#define __HYPERVISOR_net_update 5
-#define __HYPERVISOR_fpu_taskswitch 6
-#define __HYPERVISOR_yield 7
-#define __HYPERVISOR_exit 8
-#define __HYPERVISOR_dom0_op 9
-#define __HYPERVISOR_network_op 10
-#define __HYPERVISOR_set_debugreg 11
-#define __HYPERVISOR_get_debugreg 12
+#define __HYPERVISOR_set_trap_table 0
+#define __HYPERVISOR_pt_update 1
+#define __HYPERVISOR_console_write 2
+#define __HYPERVISOR_set_gdt 3
+#define __HYPERVISOR_stack_and_ldt_switch 4
+#define __HYPERVISOR_net_update 5
+#define __HYPERVISOR_fpu_taskswitch 6
+#define __HYPERVISOR_yield 7
+#define __HYPERVISOR_exit 8
+#define __HYPERVISOR_dom0_op 9
+#define __HYPERVISOR_network_op 10
+#define __HYPERVISOR_set_debugreg 11
+#define __HYPERVISOR_get_debugreg 12
+#define __HYPERVISOR_update_descriptor 13
#define TRAP_INSTR "int $0x82"
#define __cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES)))
#define ____cacheline_aligned __cacheline_aligned
-/* 0-16MB is fixed monitor space. 0-56MB is direct-mapped at top of memory.*/
+/* 0-16MB is fixed monitor space. 0-52MB is direct-mapped at top of memory.*/
#define MAX_MONITOR_ADDRESS (16*1024*1024)
#define MAX_DMA_ADDRESS (16*1024*1024)
-#define MAX_DIRECTMAP_ADDRESS (56*1024*1024)
+#define MAX_DIRECTMAP_ADDRESS (52*1024*1024)
+/* Next 4MB of virtual address space used for per-domain mappings (eg. GDT). */
+#define PERDOMAIN_VIRT_START (PAGE_OFFSET + MAX_DIRECTMAP_ADDRESS)
+#define PERDOMAIN_VIRT_END (PERDOMAIN_VIRT_START + (4*1024*1024))
/* Penultimate 4MB of virtual address space used for domain page mappings. */
-#define MAPCACHE_VIRT_START (PAGE_OFFSET + MAX_DIRECTMAP_ADDRESS)
+#define MAPCACHE_VIRT_START (PERDOMAIN_VIRT_END)
#define MAPCACHE_VIRT_END (MAPCACHE_VIRT_START + (4*1024*1024))
/* Final 4MB of virtual address space used for ioremap(). */
#define IOREMAP_VIRT_START (MAPCACHE_VIRT_END)
#include <xeno/config.h>
#include <asm/atomic.h>
+#include <asm/desc.h>
#include <xeno/list.h>
#include <hypervisor-ifs/hypervisor-if.h>
* references exist of teh current type. A change in type can only occur
* when type_count == 0.
*/
-#define PG_type_mask (7<<25) /* bits 25-27 */
-#define PGT_none (0<<25) /* no special uses of this page */
-#define PGT_l1_page_table (1<<25) /* using this page as an L1 page table? */
-#define PGT_l2_page_table (2<<25) /* using this page as an L2 page table? */
-#define PGT_l3_page_table (3<<25) /* using this page as an L3 page table? */
-#define PGT_l4_page_table (4<<25) /* using this page as an L4 page table? */
-#define PGT_writeable_page (7<<25) /* has writable mappings of this page? */
+#define PG_type_mask (7<<24) /* bits 24-26 */
+#define PGT_none (0<<24) /* no special uses of this page */
+#define PGT_l1_page_table (1<<24) /* using this page as an L1 page table? */
+#define PGT_l2_page_table (2<<24) /* using this page as an L2 page table? */
+#define PGT_l3_page_table (3<<24) /* using this page as an L3 page table? */
+#define PGT_l4_page_table (4<<24) /* using this page as an L4 page table? */
+#define PGT_gdt_page (5<<24) /* using this page in a GDT? */
+#define PGT_ldt_page (6<<24) /* using this page in an LDT? */
+#define PGT_writeable_page (7<<24) /* has writable mappings of this page? */
#define PageSlab(page) test_bit(PG_slab, &(page)->flags)
#define PageSetSlab(page) set_bit(PG_slab, &(page)->flags)
/* Part of the domain API. */
int do_process_page_updates(page_update_request_t *updates, int count);
+#define DEFAULT_GDT_ENTRIES ((FIRST_DOMAIN_GDT_ENTRY*8)-1)
+#define DEFAULT_GDT_ADDRESS ((unsigned long)gdt_table)
+
#endif /* __XENO_MM_H__ */
struct mm_struct {
unsigned long cpu_vm_mask;
+ /*
+ * Every domain has a L1 pagetable of its own. Per-domain mappings
+ * are put in this table (eg. the current GDT is mapped here).
+ */
+ l2_pgentry_t *perdomain_pt;
pagetable_t pagetable;
+ /* Current LDT selector. */
+ unsigned int ldt_sel;
+ /* Next entry is passed to LGDT on domain switch. */
+ char gdt[6];
};
+/* Convenient accessor for mm.gdt. */
+#define SET_GDT_ENTRIES(_p, _e) ((*(u16 *)((_p)->mm.gdt + 0)) = (_e))
+#define SET_GDT_ADDRESS(_p, _a) ((*(u32 *)((_p)->mm.gdt + 2)) = (_a))
+#define GET_GDT_ENTRIES(_p) ((*(u16 *)((_p)->mm.gdt + 0)))
+#define GET_GDT_ADDRESS(_p) ((*(u32 *)((_p)->mm.gdt + 2)))
+
extern struct mm_struct init_mm;
#define IDLE0_MM \
{ \
cpu_vm_mask: 0, \
+ perdomain_pt: 0, \
pagetable: mk_pagetable(__pa(idle0_pg_table)) \
}
unlazy_fpu(prev_p);
- HYPERVISOR_set_guest_stack(__KERNEL_DS, next->esp0);
+ HYPERVISOR_stack_and_ldt_switch(__KERNEL_DS, next->esp0, 0);
/*
* Save away %fs and %gs. No need to save %es and %ds, as
BUG();
enter_lazy_tlb(&init_mm, current, nr);
- HYPERVISOR_set_guest_stack(__KERNEL_DS, current->thread.esp0);
+ HYPERVISOR_stack_and_ldt_switch(__KERNEL_DS, current->thread.esp0, 0);
/* Force FPU initialization. */
current->flags &= ~PF_USEDFPU;
return ret;
}
-static inline int HYPERVISOR_set_guest_stack(
- unsigned long ss, unsigned long esp)
+static inline int HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_set_guest_stack),
- "b" (ss), "c" (esp) );
+ : "=a" (ret) : "0" (__HYPERVISOR_set_gdt),
+ "b" (frame_list), "c" (entries) );
+
+
+ return ret;
+}
+
+static inline int HYPERVISOR_stack_and_ldt_switch(
+ unsigned long ss, unsigned long esp, unsigned long ldts)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_stack_and_ldt_switch),
+ "b" (ss), "c" (esp), "d" (ldts) );
return ret;
}
return ret;
}
+static inline int HYPERVISOR_update_descriptor(
+ unsigned long pa, unsigned long word1, unsigned long word2)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_set_gdt),
+ "b" (pa), "c" (word1), "d" (word2) );
+
+
+ return ret;
+}
+
#endif /* __HYPERVISOR_H__ */